#include "cube.h"
#include <assert.h>
#include <unordered_map>
#include <functional>
#include <fstream>

// at now stage , script has already finished !!!
// I need to check face construction !!!
Cube::Cube(int n, bool enable_flatten_vertex_id){
    n_ = n;
    enable_flatten_vertex_id_ = enable_flatten_vertex_id;
    curr_n_ = 0;
    vertex_idx_ = 0;
    face_idx_ = 0;
    vertexs_table_.clear();
    faces_table_.clear();
    cells_vertexs_table_.clear();
    cells_faces_table_.clear();
    vertexhashtable_.clear();
    facehashtable_.clear();
}

int Cube::get_points_num(int n){
    int tmp = n + 1;
    return (tmp*tmp*tmp);
}

// need further verify !!!
// infer by xak !
int Cube::get_faces_num(int n){
    if(n == 1){
        return 6;
    }
    if(n == 2){
        return 36;
    }
    else {
        return (3*n*n*n)+(3*n*n)+4;
    }
}

int Cube::get_cells_num(int n){
    return (n*n*n);
}


void Cube::fill_till_n_times(){
    for(int i = 1;i <= n_;i++){
        if(i == 1){
            init();
            vertex_face_cell_nums_restrict(i);
            printf("at %d level, the vertex nums are %ld \n", i, vertexs_table_.size());
            printf("at %d level, the face nums are %ld\n", i, faces_table_.size());
            printf("at %d level, the cell nums are %ld\n", i, cells_vertexs_table_.size());
            continue;
        }
        else{
            fill_one_time(i);
            vertex_face_cell_nums_restrict(i);
            printf("at %d level, the vertex nums are %ld \n", i, vertexs_table_.size());
            printf("at %d level, the face nums are %ld\n", i, faces_table_.size());
            printf("at %d level, the cell nums are %ld\n", i, cells_vertexs_table_.size());
        }
    }
    printf("finish %d * %d * %d mesh construction !!!\n", n_, n_, n_);
    std:: cout << "ready to construct cell-face table !!!" << std::endl;
    fulfill_cells_faces_table_at_last();
    std:: cout << "finish constructing cell-face table !!!" << std::endl;
    std:: cout << "ready to print vertex-table face-table cell-vertex-table cell-face-table" << std::endl;
    display_vertex_table("./data/vertex_table");
    display_face_table("./data/face_table");
    std:: cout << "Data generation is over !!!\n";
}

// n-1 x n-1 x n-1 till n x n x n
void Cube::fill_one_time(int n){
    // first restore n-1 x n-1 x n-1 to n x n x n-1
    for(int i = 1; i <= n; i++){
        int height = i - 1;
        //one side / special vertex

        // x-ray incremental
        for(int k = 1; k <= n; k++){
            int offset_k = k - 1 ;
            vertexs_table_.push_back({offset_k, n, height});
            register_one_vertex_in_hashtable({offset_k, n, height});
            //first consider y-ray incremental
            if(i >= 2 && k >= 2){
                SmallCubeStatus st = SmallCubeStatus::INNER_X_INC;
                if(height == n-1) st = SmallCubeStatus::OUTER_X_INC;
                Vertex v[8];
                //v[7] = {n, offset_j, height};
                v[7] = {offset_k, n , height};
                v[5] = {offset_k, n-1, height};
                v[6] = {offset_k-1, n, height};
                v[4] = {offset_k-1, n-1, height};
                v[3] = {offset_k, n, height-1};
                v[1] = {offset_k, n-1, height-1};
                v[2] = {offset_k-1, n, height-1};
                v[0] = {offset_k-1, n-1, height-1};
                register_one_cell_into_face_table(v, st);
            }
            }

        // y-ray incremental
        for(int j = 1; j <= n; j++){
            int offset_j = j - 1;
            vertexs_table_.push_back({n, offset_j, height});
            register_one_vertex_in_hashtable({n, offset_j, height});
            if(i >= 2 && j >=2){
                SmallCubeStatus st = SmallCubeStatus::INNER_Y_INC;
                if(height == n-1) st = SmallCubeStatus::OUTER_Y_INC;
                Vertex v[8];
                v[7] = {n, offset_j, height};
                v[5] = {n, offset_j-1, height};
                v[6] = {n-1, offset_j, height};
                v[4] = {n-1, offset_j-1, height};
                v[3] = {n, offset_j, height-1};
                v[1] = {n, offset_j-1, height-1};
                v[2] = {n-1, offset_j, height-1};
                v[0] = {n-1, offset_j-1, height-1};
                register_one_cell_into_face_table(v, st);
            }
        }

        //other side / special vertex
        //special vertex
        vertexs_table_.push_back({n,n,height});
        register_one_vertex_in_hashtable({n,n,height});
        if(i >= 2){
            SmallCubeStatus st = SmallCubeStatus::INNER_BOUND;
            if(i == n){
                st = SmallCubeStatus::OUTER_BOUND;
            }
            Vertex v[8];
            v[7] = {n, n, height};
            v[5] = {n, n-1, height};
            v[6] = {n-1, n, height};
            v[4] = {n-1, n-1, height};
            v[3] = {n, n, height-1};
            v[1] = {n, n-1, height-1};
            v[2] = {n-1, n, height-1};
            v[0] = {n-1, n-1, height-1};
            register_one_cell_into_face_table(v, st);
        }
    }
    // then n x n x n-1 to n x n x n
    // first y then x
    for(int i = 1; i <= n+1 ; i++){
        for(int j = 1; j <= n+1 ; j++){
            vertexs_table_.push_back({i-1, j-1, n});
            register_one_vertex_in_hashtable({i-1, j-1, n});
            if(i >= 2 && j>=2){
                SmallCubeStatus st = SmallCubeStatus::TOP;
                if(i == n+1 && j < n+1){
                    st = SmallCubeStatus::TOP_X_BOUND;
                }
                if(i < n+1 && j == n+1){
                    st = SmallCubeStatus::TOP_Y_BOUND;
                }
                if(i == n+1 && j == n+1){
                    st = SmallCubeStatus::TOP_X_Y_BOUND;
                }
                Vertex v[8];
                v[7] = {i-1, j-1, n};
                v[5] = {i-1, j-2, n};
                v[6] = {i-2, j-1, n};
                v[4] = {i-2, j-2, n};
                v[3] = {i-1, j-1, n-1};
                v[1] = {i-1, j-2, n-1};
                v[2] = {i-2, j-1, n-1};
                v[0] = {i-2, j-2, n-1};
            register_one_cell_into_face_table(v, st);
            }
        }
    }
    //std::cout << "after filling one time , vertexs table's size is " << vertexs_table_.size() << std::endl;
    return;
}

void Cube::vertex_face_cell_nums_restrict(int n){
    std:: cout << "haha";
    int v_a = vertexs_table_.size();
    int v_b = get_points_num(n);
    int v_c = vertexhashtable_.size();

    int f_a = faces_table_.size();
    int f_b = facehashtable_.size();
    
    int c_a = cells_vertexs_table_.size();
    int c_b = get_cells_num(n);

    assert(v_a == v_b);
    assert(v_a == v_c);
    assert(f_a == f_b);
    assert(c_a == c_b);

    return;
}

void Cube::debug(){
    std::cout << "I just want to make a right makefile \n";
}

void Cube::init(){
    // vertex table init
    // bottom left front right back top
    // bottom  +  begin with left(anti clock) + top
    for(int k = 0; k < 2; ++k){
        for(int j = 0; j < 2; ++j){
            for(int i = 0; i < 2; ++i){
                Vertex v = {i,j,k};
                vertexs_table_.push_back(v);
                register_one_vertex_in_hashtable(v);
            }
        }
    }
    faces_table_.push_back({0,1,3,2});
    register_one_face_in_hashtable(get_pesudo_face_center_point({0,1,3,2}));
    faces_table_.push_back({0,1,5,4});
    register_one_face_in_hashtable(get_pesudo_face_center_point({0,1,5,4}));
    faces_table_.push_back({1,3,7,5});
    register_one_face_in_hashtable(get_pesudo_face_center_point({1,3,7,5}));
    faces_table_.push_back({2,3,7,6});
    register_one_face_in_hashtable(get_pesudo_face_center_point({2,3,7,6}));
    faces_table_.push_back({0,2,6,4});
    register_one_face_in_hashtable(get_pesudo_face_center_point({0,2,6,4}));
    faces_table_.push_back({4,5,7,6});
    register_one_face_in_hashtable(get_pesudo_face_center_point({4,5,7,6}));


    // cell table init
    cells_vertexs_table_.push_back({0,1,2,3,4,5,6,7});
}

Vertex Cube::get_one_vertex(int vertex_id){
    assert(vertex_id >= 0);
    assert(vertex_id < vertexs_table_.size());
    return vertexs_table_[vertex_id];
}

// 4 times
Vertex Cube::get_pesudo_face_center_point(Face f){
    Vertex v1 = vertexs_table_[f.v1];
    Vertex v2 = vertexs_table_[f.v2];
    Vertex v3 = vertexs_table_[f.v3];
    Vertex v4 = vertexs_table_[f.v4];
    Vertex v ={v1.x+v2.x+v3.x+v4.x, v1.y+v2.y+v3.y+v4.y, v1.z+v2.z+v3.z+v4.z};
    return v;
}

// 8 times
Vertex Cube::get_pesudo_cell_center_point(Cell_Vertex c){
    Vertex v1 = vertexs_table_[c.v1];
    Vertex v2 = vertexs_table_[c.v2];
    Vertex v3 = vertexs_table_[c.v3];
    Vertex v4 = vertexs_table_[c.v4];
    Vertex v5 = vertexs_table_[c.v5];
    Vertex v6 = vertexs_table_[c.v6];
    Vertex v7 = vertexs_table_[c.v7];
    Vertex v8 = vertexs_table_[c.v8];
    Vertex v ={v1.x+v2.x+v3.x+v4.x+v5.x+v6.x+v7.x+v8.x, 
               v1.y+v2.y+v3.y+v4.y+v5.y+v6.y+v7.y+v8.y, 
               v1.z+v2.z+v3.z+v4.z+v5.z+v6.z+v7.z+v8.z};
    return v;
}

VID Cube::get_one_vertex_id(Vertex &v){
    auto it = vertexhashtable_.find(v);
    assert(it != vertexhashtable_.end());
    return vertexhashtable_[v];
}

FID Cube::get_one_face_id(Face &f){
    auto it = facehashtable_.find(get_pesudo_face_center_point(f));
    if(it == facehashtable_.end()){
        debug_one_vertex(vertexs_table_[f.v1]);
        debug_one_vertex(vertexs_table_[f.v2]);
        debug_one_vertex(vertexs_table_[f.v3]);
        debug_one_vertex(vertexs_table_[f.v4]);
        assert(false);
    }
    return facehashtable_[get_pesudo_face_center_point(f)];
}

void Cube::register_one_vertex_in_hashtable(Vertex v){
    // 1. 2. get the vertex id - vertex_id_ && insert
    vertexhashtable_[v] = vertex_idx_;
    // 3. ++ vertex_id;
    vertex_idx_++;
    return;
}

void Cube::register_one_face_in_hashtable(Vertex v){
    // 1. 2. get the vertex id - vertex_id_ && insert
    facehashtable_[v] = face_idx_;
    // 3. ++ vertex_id;
    face_idx_++;
    return;
}

void Cube::display_vertex_using_id(int vertex_id){
    if(vertex_id < 0){
        std::cout << "error, vertex_id can't below zero";
    }
    assert(vertex_id < vertexs_table_.size());
    Vertex v = vertexs_table_[vertex_id];
    printf("vertex id : %d, x : %d, y : %d, z : %d", vertex_id, v.x, v.y, v.z);
}

void Cube::display_vertex_table(const std::string& filename){
    std::ofstream fout(filename);
    if (!fout) return;                // 简单错误处理
    fout << "[\n";
    for (size_t i = 0; i < vertexs_table_.size(); ++i) {
        const auto& v = vertexs_table_[i];
        fout << '\t' << '[' << v.x << ',' << v.y << ',' << v.z << ']' << '\n';
    }
    fout << "]\n";
    fout << "There are " << vertexs_table_.size() << " vertex elements\n";
    return;
}

void Cube::display_face_table(const std::string& filename){
    std::ofstream fout(filename);
    if (!fout) return;                // 简单错误处理
    fout << "[\n";
    if(enable_flatten_vertex_id_){
        for(size_t i = 0; i < faces_table_.size(); ++i){
            fout << "\t[\t";
            const auto& f = faces_table_[i];
            std::vector<VID> vec = {f.v1, f.v2, f.v3, f.v4};
            for(auto& vid_itr : vec){
                Vertex& ver = vertexs_table_[vid_itr];
                fout << '[' << ver.x << ',' << ver.y << ',' << ver.z << ']' << ' ';
            }
            fout << "\t]\n";
        }
    }
    else{
        for (size_t i = 0; i < faces_table_.size(); ++i) {
            const auto& f = faces_table_[i];
            fout << '\t' << '[' << f.v1 << ',' << f.v2 << ',' << f.v3
            << ',' << f.v4 << ']' << '\n';
    }
    }

    fout << "]\n";
    fout << "There are " << faces_table_.size() << " faces elements\n";
    return;
}

void Cube::display_cell_vertex_table(const std::string& filename){
    // std::ofstream fout(filename);
    // if (!fout) return;                // 简单错误处理

    // fout << '[';
    // fout << "\n";
    // for (size_t i = 0; i < polyhedrons_table_.size(); ++i) {
    //     const auto& p = polyhedrons_table_[i];
    //     fout << '\t' << '[' << p.f1 << ',' << p.f2 << ',' << p.f3
    //     << ',' << p.f4 << ',' << p.f5 << ',' << p.f6 
    //     << ']' << '\n';
    // }
    // fout << "]\n";
    // return;
}

void Cube::display_cell_face_table(const std::string& filename){
    // std::ofstream fout(filename);
    // if (!fout) return;                // 简单错误处理

    // fout << '[';
    // fout << "\n";
    // for (size_t i = 0; i < polyhedrons_table_.size(); ++i) {
    //     const auto& p = polyhedrons_table_[i];
    //     fout << '\t' << '[' << p.f1 << ',' << p.f2 << ',' << p.f3
    //     << ',' << p.f4 << ',' << p.f5 << ',' << p.f6 
    //     << ']' << '\n';
    // }
    // fout << "]\n";
    // return;
}

void Cube::register_one_cell_into_face_table(Vertex v[], SmallCubeStatus st){
    VID vid_list[8];
    for(int i = 0; i < 8; ++i){
        vid_list[i] = get_one_vertex_id(v[i]);
    }
    if(has_duplicate_element(vid_list)){
        std::cout << status_to_string(st) << std::endl;
        for(int i = 0;i < 8; i++){
            debug_one_vertex(vertexs_table_[vid_list[i]]);
        }
        assert(false);
    }
    //get cell-vertex table
    Cell_Vertex c = {vid_list[0], vid_list[1], vid_list[2], vid_list[3],
              vid_list[4], vid_list[5], vid_list[6], vid_list[7]};
    
    cells_vertexs_table_.push_back(c);

    // register a face's unique face
    switch (st)
    {
    case SmallCubeStatus::INNER_X_INC:{
        // 0 1 3 2
        // 2 3 7 6
        // 0 2 6 4 
        faces_table_.push_back({vid_list[0], vid_list[1], vid_list[3], vid_list[2]});
        register_one_face_in_hashtable(get_pesudo_face_center_point({vid_list[0], vid_list[1], vid_list[3], vid_list[2]}));
        faces_table_.push_back({vid_list[2], vid_list[3] , vid_list[7], vid_list[6]});
        register_one_face_in_hashtable(get_pesudo_face_center_point({vid_list[2], vid_list[3] , vid_list[7], vid_list[6]}));
        faces_table_.push_back({vid_list[0], vid_list[2], vid_list[6], vid_list[4]});
        register_one_face_in_hashtable(get_pesudo_face_center_point({vid_list[0], vid_list[2] , vid_list[6], vid_list[4]}));
        break;
    }


    case SmallCubeStatus::INNER_Y_INC:{
        //0 1 3 2
        //0 1 5 4
        //1 3 7 5
        faces_table_.push_back({vid_list[0], vid_list[1], vid_list[3], vid_list[2]});
        register_one_face_in_hashtable(get_pesudo_face_center_point({vid_list[0], vid_list[1], vid_list[3], vid_list[2]}));
        faces_table_.push_back({vid_list[0], vid_list[1], vid_list[5], vid_list[4]});
        register_one_face_in_hashtable(get_pesudo_face_center_point({vid_list[0], vid_list[1], vid_list[5], vid_list[4]}));
        faces_table_.push_back({vid_list[1], vid_list[3], vid_list[7], vid_list[5]});
        register_one_face_in_hashtable(get_pesudo_face_center_point({vid_list[1], vid_list[3], vid_list[7], vid_list[5]}));

        break;
    }

    case SmallCubeStatus::OUTER_X_INC:{
        // 0 1 3 2
        // 2 3 7 6
        // 0 2 6 4
        // 4 5 7 6
        faces_table_.push_back({vid_list[0], vid_list[1], vid_list[3], vid_list[2]});
        register_one_face_in_hashtable(get_pesudo_face_center_point({vid_list[0], vid_list[1], vid_list[3], vid_list[2]}));
        faces_table_.push_back({vid_list[2], vid_list[3] , vid_list[7], vid_list[6]});
        register_one_face_in_hashtable(get_pesudo_face_center_point({vid_list[2], vid_list[3] , vid_list[7], vid_list[6]}));
        faces_table_.push_back({vid_list[0], vid_list[2], vid_list[6], vid_list[4]});
        register_one_face_in_hashtable(get_pesudo_face_center_point({vid_list[0], vid_list[2], vid_list[6], vid_list[4]}));
        faces_table_.push_back({vid_list[4], vid_list[5], vid_list[7], vid_list[6]});
        register_one_face_in_hashtable(get_pesudo_face_center_point({vid_list[4], vid_list[5], vid_list[7], vid_list[6]}));
        break;
    }


    case SmallCubeStatus::OUTER_Y_INC:{
        //0 1 3 2
        //0 1 5 4
        //1 3 7 5
        //4 5 7 6
        faces_table_.push_back({vid_list[0], vid_list[1], vid_list[3], vid_list[2]});
        register_one_face_in_hashtable(get_pesudo_face_center_point({vid_list[0], vid_list[1], vid_list[3], vid_list[2]}));
        faces_table_.push_back({vid_list[0], vid_list[1], vid_list[5], vid_list[4]});
        register_one_face_in_hashtable(get_pesudo_face_center_point({vid_list[0], vid_list[1], vid_list[5], vid_list[4]}));
        faces_table_.push_back({vid_list[1], vid_list[3], vid_list[7], vid_list[5]});
        register_one_face_in_hashtable(get_pesudo_face_center_point({vid_list[1], vid_list[3], vid_list[7], vid_list[5]}));
        faces_table_.push_back({vid_list[4], vid_list[5], vid_list[7], vid_list[6]});
        register_one_face_in_hashtable(get_pesudo_face_center_point({vid_list[4], vid_list[5], vid_list[7], vid_list[6]}));
        break;
    }

    case SmallCubeStatus::INNER_BOUND:{
        //0 1 3 2
        //0 1 5 4
        //1 3 7 5
        //2 3 7 6
        //0 2 6 4
        faces_table_.push_back({vid_list[0], vid_list[1], vid_list[3], vid_list[2]});
        register_one_face_in_hashtable(get_pesudo_face_center_point({vid_list[0], vid_list[1], vid_list[3], vid_list[2]}));
        faces_table_.push_back({vid_list[0], vid_list[1], vid_list[5], vid_list[4]});
        register_one_face_in_hashtable(get_pesudo_face_center_point({vid_list[0], vid_list[1], vid_list[5], vid_list[4]}));
        faces_table_.push_back({vid_list[1], vid_list[3], vid_list[7], vid_list[5]});
        register_one_face_in_hashtable(get_pesudo_face_center_point({vid_list[1], vid_list[3], vid_list[7], vid_list[5]}));
        faces_table_.push_back({vid_list[2], vid_list[3] , vid_list[7], vid_list[6]});
        register_one_face_in_hashtable(get_pesudo_face_center_point({vid_list[2], vid_list[3] , vid_list[7], vid_list[6]}));
        faces_table_.push_back({vid_list[0], vid_list[2], vid_list[6], vid_list[4]});
        register_one_face_in_hashtable(get_pesudo_face_center_point({vid_list[0], vid_list[2], vid_list[6], vid_list[4]}));
        break;
    }

    case SmallCubeStatus::OUTER_BOUND:{
        //0 1 3 2
        //0 1 5 4
        //1 3 7 5
        //2 3 7 6
        //0 2 6 4
        //4 5 7 6
        faces_table_.push_back({vid_list[0], vid_list[1], vid_list[3], vid_list[2]});
        register_one_face_in_hashtable(get_pesudo_face_center_point({vid_list[0], vid_list[1], vid_list[3], vid_list[2]}));
        faces_table_.push_back({vid_list[0], vid_list[1], vid_list[5], vid_list[4]});
        register_one_face_in_hashtable(get_pesudo_face_center_point({vid_list[0], vid_list[1], vid_list[5], vid_list[4]}));
        faces_table_.push_back({vid_list[1], vid_list[3], vid_list[7], vid_list[5]});
        register_one_face_in_hashtable(get_pesudo_face_center_point({vid_list[1], vid_list[3], vid_list[7], vid_list[5]}));
        faces_table_.push_back({vid_list[2], vid_list[3] , vid_list[7], vid_list[6]});
        register_one_face_in_hashtable(get_pesudo_face_center_point({vid_list[2], vid_list[3] , vid_list[7], vid_list[6]}));
        faces_table_.push_back({vid_list[0], vid_list[2], vid_list[6], vid_list[4]});
        register_one_face_in_hashtable(get_pesudo_face_center_point({vid_list[0], vid_list[2], vid_list[6], vid_list[4]}));
        faces_table_.push_back({vid_list[4], vid_list[5], vid_list[7], vid_list[6]});
        register_one_face_in_hashtable(get_pesudo_face_center_point({vid_list[4], vid_list[5], vid_list[7], vid_list[6]}));
        break;
    }

    case SmallCubeStatus::TOP:{
        //0 1 5 4
        //0 2 6 4
        //4 5 7 6
        faces_table_.push_back({vid_list[0], vid_list[1], vid_list[5], vid_list[4]});
        register_one_face_in_hashtable(get_pesudo_face_center_point({vid_list[0], vid_list[1], vid_list[5], vid_list[4]}));
        faces_table_.push_back({vid_list[0], vid_list[2], vid_list[6], vid_list[4]});
        register_one_face_in_hashtable(get_pesudo_face_center_point({vid_list[0], vid_list[2], vid_list[6], vid_list[4]}));
        faces_table_.push_back({vid_list[4], vid_list[5], vid_list[7], vid_list[6]});
        register_one_face_in_hashtable(get_pesudo_face_center_point({vid_list[4], vid_list[5], vid_list[7], vid_list[6]}));
        break;
    }

    case SmallCubeStatus::TOP_X_BOUND:{
        //0 1 5 4
        //0 2 6 4
        //4 5 7 6
        //1 3 7 5
        faces_table_.push_back({vid_list[0], vid_list[1], vid_list[5], vid_list[4]});
        register_one_face_in_hashtable(get_pesudo_face_center_point({vid_list[0], vid_list[1], vid_list[5], vid_list[4]}));
        faces_table_.push_back({vid_list[0], vid_list[2], vid_list[6], vid_list[4]});
        register_one_face_in_hashtable(get_pesudo_face_center_point({vid_list[0], vid_list[2], vid_list[6], vid_list[4]}));
        faces_table_.push_back({vid_list[4], vid_list[5], vid_list[7], vid_list[6]});
        register_one_face_in_hashtable(get_pesudo_face_center_point({vid_list[4], vid_list[5], vid_list[7], vid_list[6]}));
        faces_table_.push_back({vid_list[1], vid_list[3], vid_list[7], vid_list[5]});
        register_one_face_in_hashtable(get_pesudo_face_center_point({vid_list[1], vid_list[3], vid_list[7], vid_list[5]}));
        break;
    }

    case SmallCubeStatus::TOP_Y_BOUND:{
        //0 1 5 4
        //0 2 6 4
        //4 5 7 6
        //2 3 7 6
        faces_table_.push_back({vid_list[0], vid_list[1], vid_list[5], vid_list[4]});
        register_one_face_in_hashtable(get_pesudo_face_center_point({vid_list[0], vid_list[1], vid_list[5], vid_list[4]}));
        faces_table_.push_back({vid_list[0], vid_list[2], vid_list[6], vid_list[4]});
        register_one_face_in_hashtable(get_pesudo_face_center_point({vid_list[0], vid_list[2], vid_list[6], vid_list[4]}));
        faces_table_.push_back({vid_list[4], vid_list[5], vid_list[7], vid_list[6]});
        register_one_face_in_hashtable(get_pesudo_face_center_point({vid_list[4], vid_list[5], vid_list[7], vid_list[6]}));
        faces_table_.push_back({vid_list[2], vid_list[3] , vid_list[7], vid_list[6]});
        register_one_face_in_hashtable(get_pesudo_face_center_point({vid_list[2], vid_list[3] , vid_list[7], vid_list[6]}));
        break;
    }

    case SmallCubeStatus::TOP_X_Y_BOUND:{
        //0 1 5 4
        //0 2 6 4
        //4 5 7 6
        //2 3 7 6
        //1 3 7 5
        faces_table_.push_back({vid_list[0], vid_list[1], vid_list[5], vid_list[4]});
        register_one_face_in_hashtable(get_pesudo_face_center_point({vid_list[0], vid_list[1], vid_list[5], vid_list[4]}));
        faces_table_.push_back({vid_list[0], vid_list[2], vid_list[6], vid_list[4]});
        register_one_face_in_hashtable(get_pesudo_face_center_point({vid_list[0], vid_list[2], vid_list[6], vid_list[4]}));
        faces_table_.push_back({vid_list[4], vid_list[5], vid_list[7], vid_list[6]});
        register_one_face_in_hashtable(get_pesudo_face_center_point({vid_list[4], vid_list[5], vid_list[7], vid_list[6]}));
        faces_table_.push_back({vid_list[2], vid_list[3] , vid_list[7], vid_list[6]});
        register_one_face_in_hashtable(get_pesudo_face_center_point({vid_list[2], vid_list[3] , vid_list[7], vid_list[6]}));
        faces_table_.push_back({vid_list[1], vid_list[3], vid_list[7], vid_list[5]});
        register_one_face_in_hashtable(get_pesudo_face_center_point({vid_list[1], vid_list[3], vid_list[7], vid_list[5]}));
        break;
    }

    default:{
        std:: cout << "error !!!\n";
        break;
    }

    }
    // if(is_special){
    //     faces_table_.push_back({vid_list[0], vid_list[1], vid_list[3], vid_list[2]});
    //     faces_table_.push_back({vid_list[0], vid_list[1], vid_list[5], vid_list[4]});
    //     faces_table_.push_back({vid_list[1], vid_list[3], vid_list[7], vid_list[5]});
    //     faces_table_.push_back({vid_list[2], vid_list[3] , vid_list[7], vid_list[6]});
    //     faces_table_.push_back({vid_list[0], vid_list[2], vid_list[6], vid_list[4]});
    //     faces_table_.push_back({vid_list[4], vid_list[5], vid_list[7], vid_list[6]});
    // }
    // else{
    //     faces_table_.push_back({vid_list[0], vid_list[1], vid_list[3], vid_list[2]});
    //     faces_table_.push_back({vid_list[0], vid_list[1], vid_list[5], vid_list[4]});
    //     faces_table_.push_back({vid_list[1], vid_list[3], vid_list[7], vid_list[5]});
    //     faces_table_.push_back({vid_list[2], vid_list[3] , vid_list[7], vid_list[6]});
    //     faces_table_.push_back({vid_list[0], vid_list[2], vid_list[6], vid_list[4]});
    //     faces_table_.push_back({vid_list[4], vid_list[5], vid_list[7], vid_list[6]});
    // }

    return;
}



void Cube::fulfill_cells_faces_table_at_last(){
    // 0,1,3,2
    // 0,1,5,4
    // 1,3,7,5
    // 2,3,7,6
    // 0,2,6,4
    // 4,5,7,6
    for(auto& c_v : cells_vertexs_table_){
        Face f1 = {c_v.v1, c_v.v2, c_v.v4, c_v.v3};
        FID  f1_id = get_one_face_id(f1);
        Face f2 = {c_v.v1, c_v.v2, c_v.v6, c_v.v5};
        FID  f2_id = get_one_face_id(f2);
        Face f3 = {c_v.v2, c_v.v4, c_v.v8, c_v.v6};
        FID  f3_id = get_one_face_id(f3);
        Face f4 = {c_v.v3, c_v.v4, c_v.v8, c_v.v7};
        FID  f4_id = get_one_face_id(f4);
        Face f5 = {c_v.v1, c_v.v3, c_v.v7, c_v.v5};
        FID  f5_id = get_one_face_id(f5);
        Face f6 = {c_v.v5, c_v.v6, c_v.v8, c_v.v7};
        FID  f6_id = get_one_face_id(f6);
        cells_faces_table_.push_back({f1_id, f2_id, f3_id,
                                      f4_id, f5_id, f6_id});
    }
}

void Cube::debug_one_vertex(Vertex v){
    std::cout << v.x << v.y << v.z << std::endl;
}

bool Cube::has_duplicate_element(VID vid_list[]){
    std::vector<VID> vec(vid_list, vid_list+8);
    assert(vec.size() == 8);
    std::sort(vec.begin(), vec.end());
    return std::adjacent_find(vec.begin(), vec.end()) != vec.end();
}

int Solution::get_num(){
    //216
    int k = 0;
    for(int i = 100;i <= 1000;i++){
        const int upper_bound = 6e7;
        if(i*i*i >= upper_bound){
            k = i;
            break;
        }
    }
    return k;
}